<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MJPG-streamer视频监控</title>
    <style>
        :root {
            --primary-color: #4285f4;
            --secondary-color: #34a853;
            --danger-color: #ea4335;
            --warning-color: #fbbc05;
            --light-gray: #f5f5f5;
            --dark-gray: #333;
            --border-radius: 6px;
            --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body {
            font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
            line-height: 1.6;
            color: var(--dark-gray);
            background-color: #f9f9f9;
            padding: 20px;
        }
        
        .container {
            max-width: 1000px;
            margin: 0 auto;
            background-color: white;
            border-radius: var(--border-radius);
            box-shadow: var(--box-shadow);
            overflow: hidden;
            padding-bottom: 20px;
        }
        
        header {
            background-color: var(--primary-color);
            color: white;
            padding: 20px;
            text-align: center;
            margin-bottom: 20px;
        }
        
        h1 {
            font-size: 24px;
            font-weight: 500;
        }
        
        .controls {
            display: flex;
            justify-content: center;
            flex-wrap: wrap;
            gap: 10px;
            padding: 15px;
            background-color: var(--light-gray);
            border-radius: var(--border-radius);
            margin: 0 20px 20px;
        }
        
        button {
            padding: 10px 20px;
            border: none;
            border-radius: var(--border-radius);
            font-weight: 500;
            cursor: pointer;
            transition: all 0.3s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            min-width: 100px;
        }
        
        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
        }
        
        button:active {
            transform: translateY(0);
        }
        
        #captureBtn {
            background-color: var(--secondary-color);
            color: white;
        }
        
        #recordBtn {
            background-color: #d23cff;
            color: white;
        }
        
        #mirrorBtn {
            background-color: var(--warning-color);
            color: var(--dark-gray);
        }
        
        #flipBtn {
            background-color: var(--warning-color);
            color: var(--dark-gray);
        }
        
        #resetBtn {
            background-color: var(--danger-color);
            color: white;
        }
        
        #colorModeBtn {
            background-color: #9c27b0;
            color: white;
        }
        
        .video-section {
            text-align: center;
            margin-bottom: 20px;
            padding: 0 20px;
        }
        
        #videoContainer {
            display: inline-block;
            border: 1px solid #ddd;
            border-radius: var(--border-radius);
            overflow: hidden;
            box-shadow: var(--box-shadow);
            max-width: 100%;
        }
        
        #videoStream {
            max-width: 100%;
            display: block;
            transition: filter 0.3s ease;
        }
        
        .capture-section {
            background-color: var(--light-gray);
            border-radius: var(--border-radius);
            padding: 20px;
            margin: 0 20px;
            text-align: center;
        }
        
        .capture-section h3 {
            margin-bottom: 15px;
            color: var(--dark-gray);
            font-weight: 500;
        }
        
        #canvas {
            display: none;
        }
        
        #capturedImage {
            max-width: 100%;
            border-radius: var(--border-radius);
            border: 1px solid #ddd;
            box-shadow: var(--box-shadow);
            margin-bottom: 15px;
            display: none;
        }
        
        #recordedVideo {
            max-width: 100%;
            border-radius: var(--border-radius);
            border: 1px solid #ddd;
            box-shadow: var(--box-shadow);
            margin-bottom: 15px;
            display: none;
        }
        
        .download-link {
            display: inline-block;
            padding: 10px 20px;
            background-color: var(--primary-color);
            color: white;
            text-decoration: none;
            border-radius: var(--border-radius);
            transition: all 0.3s ease;
            margin-top: 10px;
            display: none;
        }
        
        .download-link:hover {
            background-color: #3367d6;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
        }
        
        .status {
            text-align: center;
            margin-top: 10px;
            font-size: 14px;
            color: #666;
        }
        
        .slider-container {
            margin: 15px 0;
            padding: 0 20px;
        }
        
        .slider-label {
            display: flex;
            justify-content: space-between;
            margin-bottom: 5px;
        }
        
        .slider {
            width: 100%;
            height: 8px;
            border-radius: 4px;
            background: #ddd;
            outline: none;
            -webkit-appearance: none;
            appearance: none;
        }
        
        .slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            background: var(--primary-color);
            cursor: pointer;
        }
        
        .slider::-moz-range-thumb {
            width: 18px;
            height: 18px;
            border-radius: 50%;
            background: var(--primary-color);
            cursor: pointer;
            border: none;
        }
        
        .slider::-moz-range-track {
            width: 100%;
            height: 8px;
            border-radius: 4px;
            background: #ddd;
        }
        
        @media (max-width: 768px) {
            .controls {
                flex-direction: column;
                align-items: center;
            }
            
            button {
                width: 100%;
                max-width: 200px;
            }
        }
        
        .loader {
            display: none;
            border: 3px solid #f3f3f3;
            border-radius: 50%;
            border-top: 3px solid var(--primary-color);
            width: 20px;
            height: 20px;
            animation: spin 1s linear infinite;
            margin-right: 8px;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        .color-mode-indicator {
            display: inline-block;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            margin-left: 8px;
            vertical-align: middle;
        }
        
        .recording {
            animation: pulse 1.5s infinite;
        }
        
        @keyframes pulse {
            0% { background-color: #d23cff; }
            50% { background-color: #ff3c3c; }
            100% { background-color: #d23cff; }
        }
        
        #recordingTime {
            display: none;
            margin-top: 10px;
            font-size: 14px;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>MJPG-streamer视频监控系统</h1>
        </header>
        
        <div class="controls">
            <button id="captureBtn">
                <div class="loader" id="captureLoader"></div>
                <span>截图</span>
            </button>
            <button id="recordBtn">
                <div class="loader" id="recordLoader"></div>
                <span>开始录制</span>
            </button>
            <button id="mirrorBtn">镜像</button>
            <button id="flipBtn">反转</button>
            <button id="colorModeBtn">色彩模式 <span class="color-mode-indicator" id="colorModeIndicator"></span></button>
            <button id="resetBtn">重置</button>
        </div>
        
        <div class="slider-container">
            <div class="slider-label">
                <span>清晰度调节</span>
                <span id="sharpnessValue">100%</span>
            </div>
            <input type="range" min="50" max="150" value="100" class="slider" id="sharpnessSlider">
        </div>
        
        <div class="video-section">
            <div id="videoContainer">
                <img id="videoStream" src="http://192.168.31.139:8080/?action=stream" crossorigin="anonymous" alt="实时视频流" />
            </div>
            <p class="status" id="statusText">视频流加载中...</p>
        </div>
        
        <div class="capture-section">
            <h3>截图结果</h3>
            <canvas id="canvas"></canvas>
            <img id="capturedImage" alt="截图预览" />
            <a id="downloadLink" class="download-link">下载图片</a>
        </div>
        
        <div class="capture-section">
            <h3>录制结果</h3>
            <video id="recordedVideo" controls></video>
            <a id="downloadVideoLink" class="download-link">下载视频</a>
            <div id="recordingTime">录制时长: 00:00</div>
        </div>
    </div>

    <script>
        // 获取DOM元素
        const videoStream = document.getElementById('videoStream');
        const captureBtn = document.getElementById('captureBtn');
        const recordBtn = document.getElementById('recordBtn');
        const mirrorBtn = document.getElementById('mirrorBtn');
        const flipBtn = document.getElementById('flipBtn');
        const resetBtn = document.getElementById('resetBtn');
        const colorModeBtn = document.getElementById('colorModeBtn');
        const colorModeIndicator = document.getElementById('colorModeIndicator');
        const sharpnessSlider = document.getElementById('sharpnessSlider');
        const sharpnessValue = document.getElementById('sharpnessValue');
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        const capturedImage = document.getElementById('capturedImage');
        const downloadLink = document.getElementById('downloadLink');
        const recordedVideo = document.getElementById('recordedVideo');
        const downloadVideoLink = document.getElementById('downloadVideoLink');
        const recordingTime = document.getElementById('recordingTime');
        const statusText = document.getElementById('statusText');
        const captureLoader = document.getElementById('captureLoader');
        const recordLoader = document.getElementById('recordLoader');
        
        // 色彩模式定义
        const colorModes = [
            { name: '正常', filter: 'none', color: '#4285f4' },
            { name: '灰度', filter: 'grayscale(100%)', color: '#666' },
            { name: '复古', filter: 'sepia(100%)', color: '#8d6e63' },
            { name: '冷色调', filter: 'brightness(0.9) hue-rotate(180deg)', color: '#00bcd4' },
            { name: '暖色调', filter: 'brightness(0.9) hue-rotate(-30deg)', color: '#ff9800' },
            { name: '高对比度', filter: 'contrast(150%)', color: '#f44336' }
        ];
        
        // 录制相关变量
        let mediaRecorder;
        let recordedChunks = [];
        let recordingStartTime;
        let recordingInterval;
        let isRecording = false;
        let currentColorMode = 0;
        let isMirrored = false;
        let isFlipped = false;
        let currentSharpness = 100;
        
        // 初始化录制功能
        function initRecording() {
            // 检查浏览器是否支持MediaRecorder
            if (!window.MediaRecorder) {
                recordBtn.disabled = true;
                recordBtn.title = "您的浏览器不支持视频录制功能";
                return;
            }

            // 设置canvas尺寸与视频流相同
            canvas.width = videoStream.naturalWidth || videoStream.width;
            canvas.height = videoStream.naturalHeight || videoStream.height;
            
            // 尝试从canvas创建MediaStream
            try {
                const canvasStream = canvas.captureStream(25); // 25 FPS
                
                const options = { 
                    mimeType: 'video/webm;codecs=vp9',
                    videoBitsPerSecond: 2500000 // 2.5 Mbps
                };
                
                mediaRecorder = new MediaRecorder(canvasStream, options);
                
                mediaRecorder.ondataavailable = (event) => {
                    if (event.data.size > 0) {
                        recordedChunks.push(event.data);
                    }
                };
                
                mediaRecorder.onstop = () => {
                    const blob = new Blob(recordedChunks, { type: 'video/webm' });
                    const videoUrl = URL.createObjectURL(blob);
                    
                    recordedVideo.src = videoUrl;
                    recordedVideo.style.display = 'block';
                    
                    const timestamp = new Date().toLocaleString().replace(/[/,:]/g, '-').replace(/\s/g, '_');
                    downloadVideoLink.href = videoUrl;
                    downloadVideoLink.download = `监控录像_${timestamp}.webm`;
                    downloadVideoLink.style.display = 'inline-block';
                    
                    clearInterval(recordingInterval);
                    recordingTime.style.display = 'none';
                    
                    statusText.textContent = "录制已完成";
                    statusText.style.color = "var(--secondary-color)";
                };
                
            } catch (error) {
                console.error('录制初始化失败:', error);
                recordBtn.disabled = true;
                recordBtn.title = "录制初始化失败: " + error.message;
            }
        }

        // 开始/停止录制
        recordBtn.addEventListener('click', function() {
            if (!isRecording) {
                // 开始录制
                recordedChunks = [];
                isRecording = true;
                recordBtn.classList.add('recording');
                recordBtn.innerHTML = '<div class="loader" id="recordLoader"></div><span>停止录制</span>';
                
                // 确保canvas尺寸正确
                canvas.width = videoStream.naturalWidth || videoStream.width;
                canvas.height = videoStream.naturalHeight || videoStream.height;
                
                // 绘制当前帧到canvas
                drawVideoFrameToCanvas();
                
                // 开始录制
                mediaRecorder.start(100); // 每100ms收集一次数据
                
                // 显示录制时间
                recordingStartTime = Date.now();
                recordingInterval = setInterval(updateRecordingTime, 1000);
                recordingTime.style.display = 'block';
                
                // 开始定时绘制视频帧到canvas
                recordingFrameInterval = setInterval(drawVideoFrameToCanvas, 40); // ~25fps
                
                statusText.textContent = "正在录制...";
                statusText.style.color = "var(--danger-color)";
                
            } else {
                // 停止录制
                isRecording = false;
                recordBtn.classList.remove('recording');
                recordBtn.innerHTML = '<div class="loader" id="recordLoader"></div><span>开始录制</span>';
                
                mediaRecorder.stop();
                clearInterval(recordingFrameInterval);
            }
        });

        // 绘制视频帧到canvas
        function drawVideoFrameToCanvas() {
            ctx.save();
            
            if(isMirrored || isFlipped) {
                ctx.translate(canvas.width/2, canvas.height/2);
                if(isMirrored) ctx.scale(-1, 1);
                if(isFlipped) ctx.scale(1, -1);
                ctx.translate(-canvas.width/2, -canvas.height/2);
            }
            
            ctx.drawImage(videoStream, 0, 0, canvas.width, canvas.height);
            
            if(currentColorMode > 0) {
                applyColorFilterToCanvas(ctx, canvas.width, canvas.height, colorModes[currentColorMode].filter);
            }
            
            if(currentSharpness !== 100) {
                applySharpnessToCanvas(ctx, canvas.width, canvas.height, currentSharpness);
            }
            
            ctx.restore();
        }

        // 更新录制时间显示
        function updateRecordingTime() {
            const seconds = Math.floor((Date.now() - recordingStartTime) / 1000);
            const minutes = Math.floor(seconds / 60);
            const remainingSeconds = seconds % 60;
            
            recordingTime.textContent = `录制时长: ${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
        }
        
        // 确保视频加载后再启用截图按钮
        videoStream.onload = function() {
            captureBtn.disabled = false;
            recordBtn.disabled = false;
            statusText.textContent = "视频流已连接";
            statusText.style.color = "var(--secondary-color)";
            
            // 初始化录制功能
            initRecording();
        };
        
        // 截图功能
        captureBtn.addEventListener('click', async function() {
            try {
                // 显示加载动画
                captureLoader.style.display = "inline-block";
                captureBtn.disabled = true;
                
                // 设置canvas尺寸与视频流相同
                canvas.width = videoStream.naturalWidth || videoStream.width;
                canvas.height = videoStream.naturalHeight || videoStream.height;
                
                // 绘制当前帧到canvas
                drawVideoFrameToCanvas();
                
                // 将canvas内容转换为图片并显示
                const imageData = canvas.toDataURL('image/jpeg', 0.9);
                capturedImage.src = imageData;
                capturedImage.style.display = 'block';
                
                // 设置下载链接
                const timestamp = new Date().toLocaleString().replace(/[/,:]/g, '-').replace(/\s/g, '_');
                downloadLink.href = imageData;
                downloadLink.download = `监控截图_${timestamp}.jpg`;
                downloadLink.style.display = 'inline-block';
                
                // 显示成功状态
                statusText.textContent = "截图成功!";
                statusText.style.color = "var(--secondary-color)";
                
            } catch (error) {
                console.error('截图失败:', error);
                statusText.textContent = "截图失败: " + error.message;
                statusText.style.color = "var(--danger-color)";
            } finally {
                // 隐藏加载动画
                captureLoader.style.display = "none";
                captureBtn.disabled = false;
            }
        });
        
        // 镜像功能
        mirrorBtn.addEventListener('click', function() {
            isMirrored = !isMirrored;
            updateTransform();
            statusText.textContent = isMirrored ? "已启用镜像模式" : "已关闭镜像模式";
            statusText.style.color = isMirrored ? "var(--warning-color)" : "var(--dark-gray)";
        });
        
        // 反转功能
        flipBtn.addEventListener('click', function() {
            isFlipped = !isFlipped;
            updateTransform();
            statusText.textContent = isFlipped ? "已启用反转模式" : "已关闭反转模式";
            statusText.style.color = isFlipped ? "var(--warning-color)" : "var(--dark-gray)";
        });
        
        // 色彩模式切换
        colorModeBtn.addEventListener('click', function() {
            currentColorMode = (currentColorMode + 1) % colorModes.length;
            updateColorMode();
        });
        
        // 清晰度调节
        sharpnessSlider.addEventListener('input', function() {
            currentSharpness = parseInt(this.value);
            sharpnessValue.textContent = `${currentSharpness}%`;
            updateSharpness();
        });
        
        // 重置功能
        resetBtn.addEventListener('click', function() {
            isMirrored = false;
            isFlipped = false;
            currentColorMode = 0;
            currentSharpness = 100;
            
            updateTransform();
            updateColorMode();
            updateSharpness();
            
            sharpnessSlider.value = 100;
            sharpnessValue.textContent = "100%";
            
            statusText.textContent = "已重置所有设置";
            statusText.style.color = "var(--secondary-color)";
        });
        
        // 更新视频变换
        function updateTransform() {
            let transform = '';
            if (isMirrored) transform += 'scaleX(-1) ';
            if (isFlipped) transform += 'scaleY(-1) ';
            
            videoStream.style.transform = transform.trim();
            videoStream.style.transformOrigin = 'center center';
        }
        
        // 更新色彩模式
        function updateColorMode() {
            const mode = colorModes[currentColorMode];
            videoStream.style.filter = mode.filter;
            colorModeBtn.textContent = `色彩模式: ${mode.name}`;
            colorModeIndicator.style.backgroundColor = mode.color;
            
            statusText.textContent = `已切换至${mode.name}模式`;
            statusText.style.color = mode.color;
        }
        
        // 更新清晰度
        function updateSharpness() {
            // 对于实时视频流，我们只能通过CSS调整
            // 实际清晰度调整会在截图时应用
            const sharpness = currentSharpness / 100;
            videoStream.style.filter = `${colorModes[currentColorMode].filter} contrast(${sharpness})`;
        }
        
        // 将色彩滤镜应用到Canvas
        function applyColorFilterToCanvas(ctx, width, height, filter) {
            if(filter === 'none') return;
            
            // 创建一个临时canvas来应用滤镜
            const tempCanvas = document.createElement('canvas');
            tempCanvas.width = width;
            tempCanvas.height = height;
            const tempCtx = tempCanvas.getContext('2d');
            
            // 绘制当前内容到临时canvas
            tempCtx.drawImage(canvas, 0, 0);
            
            // 应用滤镜
            if(filter.includes('grayscale')) {
                const imageData = tempCtx.getImageData(0, 0, width, height);
                const data = imageData.data;
                for(let i = 0; i < data.length; i += 4) {
                    const gray = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
                    data[i] = data[i + 1] = data[i + 2] = gray;
                }
                tempCtx.putImageData(imageData, 0, 0);
            }
            
            if(filter.includes('sepia')) {
                const imageData = tempCtx.getImageData(0, 0, width, height);
                const data = imageData.data;
                for(let i = 0; i < data.length; i += 4) {
                    const r = data[i];
                    const g = data[i + 1];
                    const b = data[i + 2];
                    data[i] = Math.min(255, (r * 0.393) + (g * 0.769) + (b * 0.189));
                    data[i + 1] = Math.min(255, (r * 0.349) + (g * 0.686) + (b * 0.168));
                    data[i + 2] = Math.min(255, (r * 0.272) + (g * 0.534) + (b * 0.131));
                }
                tempCtx.putImageData(imageData, 0, 0);
            }
            
            if(filter.includes('hue-rotate')) {
                const imageData = tempCtx.getImageData(0, 0, width, height);
                const data = imageData.data;
                
                // 解析旋转角度
                const angleMatch = filter.match(/hue-rotate\((\d+)deg\)/);
                const angle = angleMatch ? parseInt(angleMatch[1]) : 0;
                
                // 应用色调旋转
                for(let i = 0; i < data.length; i += 4) {
                    const r = data[i];
                    const g = data[i + 1];
                    const b = data[i + 2];
                    
                    // 转换为HSL
                    const hsl = rgbToHsl(r, g, b);
                    // 调整色调
                    hsl[0] = (hsl[0] + angle/360) % 1;
                    // 转换回RGB
                    const rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
                    
                    data[i] = rgb[0];
                    data[i + 1] = rgb[1];
                    data[i + 2] = rgb[2];
                }
                tempCtx.putImageData(imageData, 0, 0);
            }
            
            if(filter.includes('brightness')) {
                const brightnessMatch = filter.match(/brightness\(([\d.]+)\)/);
                const brightness = brightnessMatch ? parseFloat(brightnessMatch[1]) : 1;
                
                const imageData = tempCtx.getImageData(0, 0, width, height);
                const data = imageData.data;
                
                for(let i = 0; i < data.length; i += 4) {
                    data[i] = Math.min(255, data[i] * brightness);
                    data[i + 1] = Math.min(255, data[i + 1] * brightness);
                    data[i + 2] = Math.min(255, data[i + 2] * brightness);
                }
                tempCtx.putImageData(imageData, 0, 0);
            }
            
            if(filter.includes('contrast')) {
                const contrastMatch = filter.match(/contrast\(([\d.]+)\)/);
                const contrast = contrastMatch ? parseFloat(contrastMatch[1]) : 1;
                
                const imageData = tempCtx.getImageData(0, 0, width, height);
                const data = imageData.data;
                
                const factor = (259 * (contrast + 255)) / (255 * (259 - contrast));
                
                for(let i = 0; i < data.length; i += 4) {
                    data[i] = factor * (data[i] - 128) + 128;
                    data[i + 1] = factor * (data[i + 1] - 128) + 128;
                    data[i + 2] = factor * (data[i + 2] - 128) + 128;
                }
                tempCtx.putImageData(imageData, 0, 0);
            }
            
            // 将处理后的图像绘制回主canvas
            ctx.drawImage(tempCanvas, 0, 0);
        }
        
        // 应用清晰度调整到Canvas
        function applySharpnessToCanvas(ctx, width, height, sharpness) {
            if(sharpness === 100) return;
            
            const tempCanvas = document.createElement('canvas');
            tempCanvas.width = width;
            tempCanvas.height = height;
            const tempCtx = tempCanvas.getContext('2d');
            
            // 绘制当前内容到临时canvas
            tempCtx.drawImage(canvas, 0, 0);
            
            // 获取图像数据
            const imageData = tempCtx.getImageData(0, 0, width, height);
            const data = imageData.data;
            
            // 应用锐化/模糊
            const amount = (sharpness - 100) / 100; // -0.5到0.5
            
            if(amount > 0) {
                // 锐化
                const radius = 1;
                const weight = amount * 10;
                
                for(let y = radius; y < height - radius; y++) {
                    for(let x = radius; x < width - radius; x++) {
                        const idx = (y * width + x) * 4;
                        
                        let r = 0, g = 0, b = 0;
                        let count = 0;
                        
                        for(let dy = -radius; dy <= radius; dy++) {
                            for(let dx = -radius; dx <= radius; dx++) {
                                if(dx === 0 && dy === 0) continue;
                                
                                const nIdx = ((y + dy) * width + (x + dx)) * 4;
                                r += data[nIdx];
                                g += data[nIdx + 1];
                                b += data[nIdx + 2];
                                count++;
                            }
                        }
                        
                        r /= count;
                        g /= count;
                        b /= count;
                        
                        data[idx] = Math.min(255, Math.max(0, data[idx] + (data[idx] - r) * weight));
                        data[idx + 1] = Math.min(255, Math.max(0, data[idx + 1] + (data[idx + 1] - g) * weight));
                        data[idx + 2] = Math.min(255, Math.max(0, data[idx + 2] + (data[idx + 2] - b) * weight));
                    }
                }
            } else if(amount < 0) {
                // 模糊
                const radius = Math.round(Math.abs(amount) * 2);
                
                for(let y = radius; y < height - radius; y++) {
                    for(let x = radius; x < width - radius; x++) {
                        const idx = (y * width + x) * 4;
                        
                        let r = 0, g = 0, b = 0;
                        let count = 0;
                        
                        for(let dy = -radius; dy <= radius; dy++) {
                            for(let dx = -radius; dx <= radius; dx++) {
                                const nIdx = ((y + dy) * width + (x + dx)) * 4;
                                r += data[nIdx];
                                g += data[nIdx + 1];
                                b += data[nIdx + 2];
                                count++;
                            }
                        }
                        
                        data[idx] = r / count;
                        data[idx + 1] = g / count;
                        data[idx + 2] = b / count;
                    }
                }
            }
            
            tempCtx.putImageData(imageData, 0, 0);
            ctx.drawImage(tempCanvas, 0, 0);
        }
        
        // RGB转HSL
        function rgbToHsl(r, g, b) {
            r /= 255, g /= 255, b /= 255;
            
            const max = Math.max(r, g, b), min = Math.min(r, g, b);
            let h, s, l = (max + min) / 2;
            
            if(max === min) {
                h = s = 0; // achromatic
            } else {
                const d = max - min;
                s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
                
                switch(max) {
                    case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                    case g: h = (b - r) / d + 2; break;
                    case b: h = (r - g) / d + 4; break;
                }
                
                h /= 6;
            }
            
            return [h, s, l];
        }
        
        // HSL转RGB
        function hslToRgb(h, s, l) {
            let r, g, b;
            
            if(s === 0) {
                r = g = b = l; // achromatic
            } else {
                const hue2rgb = (p, q, t) => {
                    if(t < 0) t += 1;
                    if(t > 1) t -= 1;
                    if(t < 1/6) return p + (q - p) * 6 * t;
                    if(t < 1/2) return q;
                    if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
                    return p;
                };
                
                const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
                const p = 2 * l - q;
                
                r = hue2rgb(p, q, h + 1/3);
                g = hue2rgb(p, q, h);
                b = hue2rgb(p, q, h - 1/3);
            }
            
            return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
        }
        
        // 处理视频加载错误
        videoStream.onerror = function() {
            statusText.textContent = "无法加载视频流，请检查URL或网络连接";
            statusText.style.color = "var(--danger-color)";
            captureBtn.disabled = true;
            recordBtn.disabled = true;
        };
        
        // 初始禁用按钮，直到视频加载
        captureBtn.disabled = true;
        recordBtn.disabled = true;
        
        // 初始化色彩模式指示器
        updateColorMode();
    </script>
</body>
</html>